"""Header_Information
------------------------------------
    File_Name: path_para
    Author: RR9
    Date: 2024/09/20
    Description: 路径参数
------------------------------------
"""
from fastapi import APIRouter, Query, Path, Body, Cookie, Header, File, UploadFile
from fastapi import HTTPException, status
from fastapi.encoders import jsonable_encoder
from fastapi import Depends
from pydantic import (BaseModel, Field, HttpUrl, EmailStr, ValidationError, field_validator)
from typing import List, Set
from enum import Enum
from typing import Annotated, Union, Any
from uuid import UUID
from app.exception.exceptions import CustomException
from datetime import datetime, timedelta, timezone, time

router = APIRouter()


# 预设值声明
class ColorEnum(str, Enum):
    RED = 'red'
    GREEN = 'green'
    BLUE = 'blue'
    ORANGE = 'orange'
    YELLOW = 'yellow'


# 虚拟数据
fake_items_db = [
    {"item_name": "9001"},
    {"item_name": "9002"},
    {"item_name": "9003"},
    {"item_name": "9004"},
    {"item_name": "9005"},
    {"item_name": "9006"},
    {"item_name": "9007"},
    {"item_name": "9008"},
    {"item_name": "9009"}
]


# 类型声明
@router.get("/item1/{item_id}/", summary="路径参数————类型声明")
async def item1(item_id: int):  # 类型声明
    """路径参数——类型声明"""
    return {"item_id": item_id}


# 预设值
@router.get("/item2/{color}/", summary="路径参数————枚举预设值")
async def item2(color: ColorEnum):
    """路径参数——枚举预设值"""
    # 假设路径参数为 "red",当进入函数体时：
    # 1. color 即为 ColorEnum.RED项, color is ColorEnum.RED 为真
    # 2. color.value 相当于 ColorEnum.RED.value, 其值为 'red'
    return {"您输入的颜色为：": color}


# 声明的参数不是路径参数时，路径操作函数会把该参数自动解释为查询参数


@router.get("/item3/", summary="查询参数——默认值")
async def item3(skip: int = 0, limit: int = 10):
    """查询参数————默认值"""
    return fake_items_db[skip:skip + limit]


@router.get("/item4/", summary="查询参数——可选参数")
async def item4(uid: str, q: str | None = None, flag: bool = False):
    """查询参数————可选参数\n
    uid 必选的str参数\n
    q 参数可选，不传则为None\n
    flag 默认False的 布尔类型参数
    """

    if q:
        return {"uid": uid, "q": q, "flag": flag}
    return {"uid": uid, "flag": flag}


class Item5(BaseModel):
    """数据模型
    用于自动数据验证、类型转换等
    """
    name: str = Field(default="王天一", max_length=5, description="用户名称")
    description: str | None = None
    price: float
    tax: float | None = None


@router.post("/item5/", summary="请求体")
async def itme5(item: Item5):
    """请求体"""
    return item


@router.post("/item6/{uid}/", summary="请求体 + 路径参数 + 查询参数")
async def itme6(uid: int, item: Item5, q: str | None = None):
    """请求体 + 路径参数 + 查询参数"""
    return {"uid": uid, **item.dict(), "q": q}


@router.post("/item7/", summary="Query作为查询参数额外校验")
async def itme7(q: str | None = Query("天王盖地虎", description="查询参数额外校验", max_length=10, min_length=5)):
    """查询参数额外校验"""
    results = {"uid": "90001"}
    if q is not None:
        results.update({"q": q})
    return results


@router.post("/item8/", summary="查询参数列表 + 默认值")
async def itme8(q: List[str] | None = Query(["北方", "泼水"], description="参数列表")):
    """查询参数列表 + 默认值"""
    query_item = {"q": q}
    return query_item


@router.post("/item9/", summary="弃用参数")
async def itme9(q: List[str] | None = Query(["北方", "泼水"], description="参数列表"),
                u: str = Query("dangdang", deprecated=True)):
    """弃用参数"""
    query_item = {"q": q, "u": u}
    return query_item


@router.post("/item10/{item_id}/", summary="路径参数和数值校验")
async def itme10(item_id: Annotated[int, Path(description="添加描述", gt=5)],
                 q: int | None = Query(None, description="查询参数q", gt=8)
                 ):
    """路径参数校验
    gt：大于（greater than）\n
    ge：大于等于（greater than or equal）\n
    lt：小于（less than）\n
    le：小于等于（less than or equal）
    """
    result = {"item_id": item_id}
    if q:
        result.update({"q": q})
    return result


class Item11(BaseModel):
    b: int


@router.post("/item11/", summary="请求体中单一值及校验")
async def itme11(a: Annotated[int, Body(ge=5, le=99)], b: Annotated[int, Body()]):
    """请求体中单一值及校验"""
    return {"a": a, "b": b}


class Item12(BaseModel):
    name: str
    addr: str


@router.post("/item12/", summary="嵌入单个请求体参数")
async def itme12(item: Annotated[Item12, Body(embed=True)]):
    """嵌入单个请求体参数
    将单个请求体放在一个JSON对象里面\n
    Body(embed=True)
    """
    return {"item": item}


class Item13(BaseModel):
    name: str | None = Field(None, max_length=10)
    age: int = Field(18, le=88)


@router.post("/item13/", summary="请求体模型声明与校验")
async def itme13(item: Annotated[Item13, Body(embed=True)]):
    """请求体模型声明与校验"""
    return {"item": item}


class Image(BaseModel):
    name: str
    url: HttpUrl


class Item14(BaseModel):
    name: str
    description: str | None = None
    price: float
    tax: float | None = None
    # tags: list[str] = []  # 列表
    # tags: Set[str] = set()  # 按文档写法set() 不起作用；
    tags: Set[str]  # 集合，不重复数据
    image: Image | None = None
    imagelist: list[Image] | None = None


@router.post("/item14/", summary="请求体字段嵌套模型")
async def itme14(item: Item14):
    """请求体字段嵌套模型"""
    return {"item": item}


class Item15(BaseModel):
    name: str = Field(max_length=4)
    # name: str
    description: str | None = None
    price: float
    tax: float | None = None
    image: Image | None = None

    # @field_validator这种写法可以返回自定义异常信息
    # @field_validator('price')
    # @classmethod
    # def name_must_contain_space(cls, v: float) -> float:
    #     if v < 3:
    #         raise ValueError("价格大于3")
    #     return v

    model_config = {
        "json_schema_extra": {
            "examples": [
                {
                    "name": "Foo",
                    "description": "A very nice Item",
                    "price": 35.4,
                    "tax": 3.2,
                    "image": {
                        "name": "张三",
                        "url": "https://i.imgur.com"
                    }
                }
            ],
        }
    }


class Item15_2(BaseModel):
    name: str = Field(examples=["Boo"])
    description: str = Field(default=None, examples=["B very nice Item"])
    price: float = Field(examples=[35.4])
    tax: float = Field(default=None, examples=[3.2])


@router.post("/item15/", summary="模式的额外信息——示例")
async def itme15(item: Item15):
    """模式的额外信息——示例\n
    ① 模型的model_config配置; ② 模型Field中 examples 属性
    """
    return {"item": item}


@router.post("/item16/", summary="额外数据类型")
async def itme16(
        item_id: Annotated[UUID, Body()],
        start_datetime: Annotated[datetime, Body()],
        end_datetime: Annotated[datetime, Body()],
        process_after: Annotated[timedelta, Body()],
        repeat_at: Annotated[time | None, Body()] = None
):
    """额外数据类型"""
    start_process = start_datetime + process_after
    duration = end_datetime - start_process
    return {
        "item_id": item_id,
        "start_datetime": start_datetime.strftime("%Y-%m-%d %H:%M:%S"),
        "end_datetime": end_datetime.strftime("%Y-%m-%d %H:%M:%S"),
        "process_after": process_after,
        "repeat_at": repeat_at.strftime("%H:%M:%S"),
        "start_process": start_process.strftime("%Y-%m-%d %H:%M:%S"),
        "duration": duration,
    }


@router.post("/item17/", summary="Cookit参数")
async def itme17(ads_id: Annotated[str | None, Cookie(),] = None):
    """Cookit参数"""
    print('ads_id', ads_id)
    return {"ads_id": ads_id}


@router.post("/item18/", summary="Header参数")
async def itme18(x_token: Annotated[list[str] | None, Header()] = None):
    """Header参数"""
    print('x_token', x_token)
    return {"X-Token values": x_token}


class Item19(BaseModel):
    name: str = Field(max_length=5)
    description: str | None = Field(None, max_length=5)
    price: float
    tax: float | None = None
    tags: list[str] = []

    @field_validator("description")
    def description_validator(cls, v):
        return 'yang' + v


@router.post("/item19/", summary="响应模型")
async def itme19(item: Item19) -> Item19:
    """响应模型"""
    return item


class UserIn(BaseModel):
    username: str
    password: str
    email: EmailStr
    full_name: str | None = None


class UserOut(BaseModel):
    username: str
    email: EmailStr
    full_name: str | None = None


@router.post("item/20/", response_model=UserOut, summary="响应模型2")
async def itme20(user: UserIn) -> Any:
    """响应模型2"""
    return user


class Item21(BaseModel):
    name: str
    description: str | None = None
    price: float
    tax: float = 10.5
    tags: List[str] = []


items21 = {
    "foo": {"name": "Foo", "price": 50.2},
    "bar": {"name": "Bar", "description": "The bartenders", "price": 62, "tax": 20.2},
    "baz": {"name": "Baz", "description": None, "price": 50.2, "tax": 10.5, "tags": []},
}


@router.get(
    "/item21/{item_id}/",
    response_model=Item21,
    response_model_include=["name", "description"]
)
async def read_item(item_id: str):
    """响应模型编码参数\n
    response_model_exclude_unset = True 不返回默认值，仅返回真实的值\n
    response_model_include : 仅返回包含字段
    """
    return items21[item_id]


class UserBase22(BaseModel):
    username: str
    email: EmailStr
    full_name: str | None = None


class UserIn22(UserBase22):
    password: str


class UserInDB22(UserBase22):
    hashed_password: str


def fake_password_hasher(password: str) -> str:
    return "supersecret" + password


def fake_save_user(user_in: UserIn):
    hashed_password = fake_password_hasher(user_in.password)
    user_in_db = UserInDB22(**user_in.dict(), hashed_password=hashed_password)
    print("User saved! ...not really")
    print('user_in_db', user_in_db.dict())
    return user_in_db


@router.post("/item22/", summary="更多响应模型————减少重复")
async def item22(user_in: UserIn):
    """更多响应模型————减少重复"""
    user_saved = fake_save_user(user_in)
    return user_saved


class BaseItem23(BaseModel):
    description: str
    type: str


class CarItem23(BaseItem23):
    type: str = "car"


class PlaneItem23(BaseItem23):
    type: str = "plane"
    size: int


item23 = {
    "item1": {"description": "All my friends drive a low rider", "type": "car", "addr": "贵州"},
    "item2": {
        "description": "Music is my aeroplane, it's my aeroplane",
        "type": "plane",
        "size": 5,
        "addr": "重庆"
    },
}


@router.get("/item23/{item_id}/", response_model=Union[PlaneItem23, CarItem23], summary="响应模型————联合")
async def read_item(item_id: str):
    """响应模型————联合Union"""
    return item23[item_id]


class Item24(BaseModel):
    name: str
    description: str


item24_list = [
    {"name": "Foo", "description": "There comes my hero"},
    {"name": "Red", "description": "It's my aeroplane"},
]


@router.get("/item24/", summary="响应模型————列表", response_model=list[Item24])
async def item24():
    """响应模型————列表"""
    return item24_list


@router.post("/item25/", summary="文件————小文件，存内存中")
async def item25(file: bytes = File()):
    """上传文件"""
    return {"file_size": len(file)}


@router.post("/item26/", summary="上传文件————图片视频二进制大文件，存磁盘中")
async def item26(file: UploadFile):
    print("file:::", file)
    return {"file_name": file.filename}


@router.post("/item27/{item_id}/", summary="错误处理————HTTPException")
async def item27(item_id: str):
    """错误处理————HTTPException"""
    item27 = {"foo": "The Foo Wrestlers"}
    if item_id not in item27:
        raise HTTPException(status_code=404, detail="item_id not found")
    return {"item": item27[item_id]}


@router.post("/item28/{name}/", summary="错误处理————自定义异常处理")
async def item28(name: str):
    """错误处理————自定义异常处理"""
    if name == "tian":
        raise CustomException(message=name)
    return {"custom_name": name}


@router.get("/item29/{id}", summary="文档字符串————多行")
async def item29(id: int):
    """文档字符串————多行

    1. 有序列表
    2. ....
    3. ...
    - 无序列表
    - ...
    - ...
    - **粗体**
    - *斜体*
    """
    return {"id": id}


@router.get("/item30/{message}/", summary="响应描述", response_description="响应描述文本")
async def item30(message: Any):
    """响应描述文本"""
    return {"message": message}


@router.get("item31/{message}/", deprecated=True, summary="弃用路径操作")
async def item31(message: Any):
    """弃用路径操作"""
    return {"message": message}


class Item32(BaseModel):
    title: str
    date: datetime
    description: str | None = None

    @classmethod
    def from_dict_with_formatted_timestamp(cls, data):
        # 从字典中创建 Item 实例
        item = cls(**data)
        # 将格式化后的时间戳作为一个属性添加到实例中（注意：这不是推荐的做法）
        item.date = item.date.strftime('%Y-%m-%d %H:%M:%S')
        return item

    @property
    def formatted_timestamp(self):
        return self.date.strftime("%Y-%m-%d %H:%M:%S")


@router.post("/item32/{id}/", summary="JSON兼容编码器")
async def item32(id: str, item: Item32):
    """JSON兼容编码器"""
    print(id, item)
    print(item)
    print('*' * 20)
    print('999999', jsonable_encoder(item))
    print('*' * 20)
    print('时间：', item.formatted_timestamp)
    json_item = jsonable_encoder(item)
    dict_item = item.dict()
    dict_item['date'] = item.formatted_timestamp
    return {"id": id, "item": item, "item_json": json_item, "dict_item": dict_item,
            "dict_item22": item.from_dict_with_formatted_timestamp(item.dict())}


async def common_parameters(
        q: str | None = None, skip: int = 0, limit: int = 100
):
    return {"q": q, "skip": skip, "limit": limit}


class CommonQueryParams:
    def __init__(self, q: str | None = None, skip: int = 1, limit: int = 120):
        self.q = q
        self.skip = skip
        self.limit = limit


@router.get("/item33/", summary="依赖项————函数定义")
async def item33(commons: dict = Depends(common_parameters)):
    """依赖注入————函数定义"""
    return commons


@router.post("/item34/", summary="依赖项————类定义")
async def item34(commons: CommonQueryParams = Depends()):
    """依赖注入————类定义"""
    return commons


def query_q(q: str | None = None):
    return q


def query_q_or_cookie(q: str = Depends(query_q), last_query: str | None = Cookie(default=None)):
    if not q:
        return last_query
    return q


@router.get("/item35/", summary="依赖项————子依赖项")
async def item35(query_or_defaullt: str = Depends(query_q_or_cookie)):
    """依赖项————子依赖项"""
    return {"query_or_defaullt": query_or_defaullt}


async def verify_token(x_token: str = Header()):
    if x_token != "bs_token":
        raise HTTPException(status_code=400, detail=f"""当前token值【{x_token}】无效""")


async def verify_key(x_key: str = Header()):
    if x_key != "bs_key":
        raise HTTPException(status_code=400, detail=f"""当前ken值【{x_key}】无效""")


@router.post('/item36/', summary="装饰器依赖项",
             dependencies=[Depends(verify_token), Depends(verify_key)])
async def item36():
    return [{"name": "张三", "message": "装饰器依赖项"}]


"""安全性——OAuth2 后面更新"""

"""
以下测试
"""


@router.post("/item99/", summary="测试")
async def itme99(item: dict[int, float]):
    return {"item": item}
